---
title: |
  Replication material: Schulte-Cloos (2021) 'Political potentials, deep-seated nativism and the success of the German AfD' in: Frontiers of Political Science, doi: 10.3389/fpos.2021.698085.
author: |
  Julia Schulte-Cloos
date: |
  `r lubridate::today()`
output:
  bookdown::html_document2:
    theme: flatly
    highlight: textmate
    toc: yes
    toc_float:
      collapsed: no
      smooth_scroll: no
    number_sections: yes
    code_folding: hide
    toc_depth: 2 
link-citations: true
bibliography: [replication_references.bib]
---



```{r setup, include=FALSE, eval=TRUE}

pacman::p_load(
  tidyverse,
  knitr,
  kableExtra,
  sf,
  RColorBrewer,
  tictoc,
  spdep,
  gridExtra,
  colorspace,
  scales,
  broom,
  jcolors,
  lubridate,
  spdep,
  spatialreg,
  showtext,
  modelsummary,
  furrr
)


# runif(1,0, 10^8) # 40569693
set.seed(40569693)

knitr::opts_chunk$set(
  message = FALSE,
  warning = FALSE,
  cache = FALSE,
  echo = FALSE
)
```


```{r set-ggplot-font-html, eval=knitr::is_html_output()}

## add a font from google fonts
font_add_google(
  name = "Fira Sans",
  family = "Fira Sans"
)

ggplot_font <- "Fira Sans"
```


```{r theme-set-ggplot}


ggplot2::theme_set(
  theme_bw() +
    theme(text = element_text(family = ggplot_font)) +
    theme(
      plot.title = element_text(
        hjust = 0.5
      ),
      plot.subtitle = element_text(
        hjust = 0.5
      )
    )
)
```


```{r load-afd-spatial-data}

afd_spatial <- read_csv(file = "./data/afd_municipality_panel.csv") %>%
  left_join(
    .,
    sf::read_sf("./data/afd_spatial.shp")
  ) %>%
  sf::st_as_sf()
```


# Data sources and data operationalization 

## Electoral data 

The electoral data is provided by the Federal Returning Officer and is publicly available for each Federal Election. The data is released on the level of electoral wards (i.e., polling stations), which include both physical voting stations and mail voting stations. Polling stations do not represent a meaningful units of analysis as they cannot be uniquely identified and traced across time and across the different elections. Therefore, we need to aggregate the polling level data to the unit of municipalities. The German municipalities correspond to the 'LAU' level of the European regional classification. We consider both votes cast in a physical voting station and by mail. It is increasingly common to vote by mail among German citizens.^[ In the Federal election 2013, the share of votes cast by mail among all votes was 24.3 percentage, whereas in 2017, this share was even 28.6 percentage.] As some municipalities share a mail voting district, I apportion the respective mail votes to the individual municipalities according to the number of citizens who applied for mail voting.

As discussed in the main article, German municipalities have been subject to administrative reforms over the period of 2009-2019. Data on the administrative reforms is publicly available and released by the Federal Statistical Office. As these administrative changes do not occur at random, but may instead reflect the local community-level decline in socio-structural and demographic terms, it is important to account for these administrative reforms. To do so, I link the data on the various administrative reforms to the data provided by the Federal Returning Officer, helping me to trace the history of each municipality and its division in several different municipalities across previous election years. I then consider the most recent state of administrative division (EP elections 2019) as universe of all German municipalities and aggregate the number of votes cast in municipalities that later merged to the respective level of their future administrative division. As I rely on a design that estimates *within-county variation* in electoral support, counties that consist of a single municipality are excluded from the analysis.


## Dependent variable 

The outcome of interest is the municipal level support for the populist right AfD in all nation-wide elections that the party has contested since its existence, i.e., the national elections in 2013 and 2017 and the EP elections in 2014 and 2019. 

In addition to studying the levels of support for the AfD, I also look at the change in electoral support across the respective elections to study the *Multiplier Hypothesis* (H2).


## Spatial dependence on the dependent variable


To empirically assess the degree of spatial dependence in the data, as a first step, we need to decide on a strategy on how to identify all neighbouring observations in the data. A commonly used approach when dealing with areal data in the social science is to consider all those observations neighbours that share contiguous polygons to the respective municipality in question, the so-called "queen contiguity definition" [@Anselin.1988, p.18]. The definition of the spatial weights matrix is critical as it imposes direct constraints on our ability to diagnose and model spatial autocorrelation [@Darmofal.2015, chapter 2].

I first address the question whether there is a univariate spatial autocorrelation in the absence of any covariates by studying the global Moran I statistic. As in most social science applications of spatial data, I find a strong spatial dependence of the populist right vote share since the very existence of the AfD. 



```{r covariates-vector}

covariates <- c(
  "population_thin",
  "population_intermediate",
  "pop_change_since_2009",
  "population_density",
  "area",
  "invalid_share_2009",
  "abstention_share_2009"
)
```

```{r afd-nest-data}

# nest spatial data,
afd_spatial_nest <- afd_spatial %>%
  group_by(election_date, election_type, east) %>%
  nest()
```

```{r afd-growth-nest-data}

afd_growth_spatial <- afd_spatial %>%
  arrange(election_date) %>%
  group_by(ags, election_type) %>%
  mutate(vote_delta = vote_share - dplyr::lag(vote_share)) %>%
  filter(!is.na(vote_delta))

# nest growth spatial data
afd_growth_spatial_nest <- afd_growth_spatial %>%
  ungroup() %>%
  filter(!is.na(.)) %>%
  group_by(election_date, election_type, east) %>%
  nest()
```


```{r regression-model-equations}

# model equation
model_eq <- function(election_type) {
  case_when(
    election_type == "Parliament" ~ paste0(
      "vote_share ~ rr_vote_share_2009 + ",
      paste(covariates, collapse = " + "),
      " + as.factor(afd_candidate)",
      " + as.factor(county_id)"
    ),
    election_type == "EP" ~ paste0(
      "vote_share ~ rr_vote_share_2009 + ",
      paste(covariates, collapse = " + "),
      " + as.factor(county_id)"
    )
  )
}



# model equation
model_growth_eq <- function(election_type) {
  case_when(
    election_type == "Parliament" ~ paste0(
      "vote_delta ~ rr_vote_share_2009 + ",
      paste(covariates, collapse = " + "),
      " + as.factor(afd_candidate)",
      " + as.factor(county_id)"
    ),
    election_type == "EP" ~ paste0(
      "vote_delta ~ rr_vote_share_2009 + ",
      paste(covariates, collapse = " + "),
      " + as.factor(county_id)"
    )
  )
}
```


```{r spatial-dependence-parameters, include=FALSE}


continuous_variables <- c(
  "vote_share",
  "vote_delta",
  "rr_vote_share_2009",
  "rr_vote_share_2005",
  "pop_change_since_2009",
  "pop_change_since_2005",
  "population_density",
  "population_density_2009",
  "area",
  "invalid_share_2009",
  "abstention_share_2009",
  "invalid_share_2005",
  "abstention_share_2005"
)


tic()
# standardise variables
afd_spatial_nest <- afd_spatial_nest %>%
  ungroup() %>%
  mutate(
    data_std = map(
      data,
      ~ ungroup(.) %>%
        # keep only subset of relevant variables
        select(
          ., state_id, county_id, municipality,
          geometry,
          any_of(covariates), afd_candidate, eligible, eligible_2009,
          any_of(continuous_variables)
        ) %>%
        group_by(., state_id) %>%
        mutate(., across(any_of(continuous_variables), scale))
    ),
    # estimate the naive, ols model on the spatial dataset
    model_eq = map(
      election_type,
      ~ model_eq(.)
    ),
    lm_model = map2(
      data_std,
      model_eq,
      ~ lm(.y,
        data = .x,
        weights = eligible / sum(eligible)
      )
    ),
    tidy_lm = map(
      lm_model,
      ~ tidy(.)
    ),
    # add residuals
    data_std = map2(
      data_std,
      lm_model,
      ~ ungroup(.x) %>%
        mutate(ols_resid = resid(.y))
    ),
    # compute the neighbourhood matrix
    afd_spatial.nb = map(
      data_std,
      # all contiguous neighbours (poly2nb) are considered neighbours
      ~ spdep::poly2nb(.,
        queen = T
      )
    ),
    # compute the weight matrix
    afd_spatial.lw = map(
      afd_spatial.nb,
      ~ spdep::nb2listw(.,
        style = "W",
        zero.policy = T
      )
    )
  ) %>%
  select(-model_eq)
toc()
```

```{r spatial-dependence-parameters-growth, include=FALSE}

# estimate the naive, ols model on the spatial dataset
afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  ungroup() %>%
  mutate(
    data_std = map(
      data,
      ~ ungroup(.) %>%
        # keep only subset of relevant variables
        select(
          ., state_id, county_id, municipality,
          geometry,
          any_of(covariates), afd_candidate, eligible,
          any_of(continuous_variables)
        ) %>%
        group_by(., state_id) %>%
        mutate(across(any_of(continuous_variables), scale))
    ),
    model_growth_eq = map(
      election_type,
      ~ model_growth_eq(.)
    ),
    # naive OLS model
    lm_model = map2(
      data_std,
      model_growth_eq,
      ~ lm(.y,
        data = .x,
        weights = eligible / sum(eligible)
      )
    ),
    tidy_lm = map(
      lm_model,
      ~ tidy(.)
    ),
    # add residuals
    data_std = map2(
      data_std,
      lm_model,
      ~ ungroup(.x) %>%
        mutate(ols_resid = resid(.y))
    ),
    # compute the neighbourhood matrix
    afd_spatial.nb = map(
      data_std,
      # all contiguous neighbours (poly2nb) are considered neighbours
      ~ spdep::poly2nb(.,
        queen = T
      )
    ),
    # compute the weight matrix
    afd_spatial.lw = map(
      afd_spatial.nb,
      ~ spdep::nb2listw(.,
        style = "W",
        zero.policy = T
      )
    )
  ) %>%
  select(-model_growth_eq)
```

```{r moranI-univariate}

afd_spatial_nest <- afd_spatial_nest %>%
  mutate( # compute the monte carlo moran I stat
    moranI_mc_vote_share = map2(
      data_std,
      afd_spatial.lw,
      ~ moran.mc(.x$vote_share,
        listw = .y,
        nsim = 999,
        alternative = "greater",
        zero.policy = T
      )
    ),
    # tidy the monte carlo moran
    moranI_mc_vote_share = map(
      moranI_mc_vote_share,
      ~ tidy(.)
    ),
    # extract statistic
    moranI_mc_vote_share_stat = map(
      moranI_mc_vote_share,
      ~ select(
        .,
        statistic
      ) %>%
        unnest(.)
    ),
    moranI_mc_vote_share_pvalue = map(
      moranI_mc_vote_share,
      ~ select(
        .,
        p.value
      ) %>%
        unnest(.)
    )
  )








afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  mutate( # compute the monte carlo moran I stat
    moranI_mc_vote_delta = map2(
      data_std,
      afd_spatial.lw,
      ~ moran.mc(.x$vote_delta,
        listw = .y,
        nsim = 999,
        alternative = "greater",
        zero.policy = T
      )
    ),
    # tidy the monte carlo moran
    moranI_mc_vote_delta = map(
      moranI_mc_vote_delta,
      ~ tidy(.)
    ),
    # extract statistic
    moranI_mc_vote_delta_stat = map(
      moranI_mc_vote_delta,
      ~ select(
        .,
        statistic
      ) %>%
        unnest(.)
    ),
    moranI_mc_vote_delta_pvalue = map(
      moranI_mc_vote_delta,
      ~ select(
        .,
        p.value
      ) %>%
        unnest(.)
    )
  )
```

```{r table-univariate-moranI}

# prepare a table
moran_univariate_table <- afd_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    moranI_mc_vote_share_stat,
    moranI_mc_vote_share_pvalue
  ) %>%
  mutate(moranI_mc_vote_share_stat = map(
    moranI_mc_vote_share_stat,
    ~ round(., digits = 2)
  )) %>%
  mutate(year = lubridate::year(election_date)) %>%
  ungroup() %>%
  select(-moranI_mc_vote_share_pvalue, -election_date) %>%
  arrange(desc(east), desc(election_type), year) %>%
  mutate(moranI_mc_vote_share_stat = as.numeric(unlist(moranI_mc_vote_share_stat))) %>%
  pivot_wider(
    names_from = c(east),
    values_from = moranI_mc_vote_share_stat
  ) %>%
  rename(
    east_moranI_univariate_afd = `East Germany`,
    west_moranI_univariate_afd = `West Germany`
  )


# table univariate moranI growth
# prepare a table
moran_univariate_table_growth <- afd_growth_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    moranI_mc_vote_delta_stat,
    moranI_mc_vote_delta_pvalue
  ) %>%
  mutate(moranI_mc_vote_delta_stat = map(
    moranI_mc_vote_delta_stat,
    ~ round(., digits = 2)
  )) %>%
  mutate(year = lubridate::year(election_date)) %>%
  ungroup() %>%
  select(-moranI_mc_vote_delta_pvalue, -election_date) %>%
  arrange(desc(east), desc(election_type), year) %>%
  mutate(moranI_mc_vote_delta_stat = as.numeric(unlist(moranI_mc_vote_delta_stat))) %>%
  pivot_wider(
    names_from = c(east),
    values_from = moranI_mc_vote_delta_stat
  ) %>%
  rename(
    east_moranI_univariate_afd_growth = `East Germany`,
    west_moranI_univariate_afd_growth = `West Germany`
  )



moran_univariate_table <- full_join(
  moran_univariate_table,
  moran_univariate_table_growth,
  by = c("year", "election_type")
) %>%
  select(election_type, year, starts_with("west"), starts_with("east"))



minimum_moran_I_without_fixed_effects <- round(
  min(moran_univariate_table$west_moranI_univariate_afd_growth,
      moran_univariate_table$west_moranI_univariate_afd,
      moran_univariate_table$east_moranI_univariate_afd_growth,
      moran_univariate_table$east_moranI_univariate_afd, na.rm = T), 
  digits = 2)


maximum_moran_I_without_fixed_effects <- round(
  max(moran_univariate_table$west_moranI_univariate_afd_growth,
      moran_univariate_table$west_moranI_univariate_afd,
      moran_univariate_table$east_moranI_univariate_afd_growth,
      moran_univariate_table$east_moranI_univariate_afd, na.rm = T), 
  digits = 2)

```



```{r univariate-moranI-table}

options(knitr.kable.NA = "")
kable(moran_univariate_table,
  booktabs = T,
  escape = FALSE,
  col.names = c("Election", "Year", 
                "AfD", "$\\Delta$ AfD", 
                "AfD", "$\\Delta$ AfD"),
  caption = "Global Moran's I Statistic (Univariate)"
) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 2,
    "West Germany" = 2,
    "East Germany" = 2
  )) %>%
  kableExtra::footnote(
    general_title = "",
    general = "Pseudo p-values: 0.001 (smallest possible value with 999 random permutations).",
    threeparttable = TRUE,
    footnote_as_chunk = T
  )  %>% 
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"))
```


To model the spatial dependence on the dependent variable, it is critical to understand whether the spatial dependence persists after controlling for covariates, and if so, whether spatial lag dependence or spatial error dependence accounts for the spatial dependence in the residuals of the model. I first discuss these covariates, then I address this issue.  



## Independent variables 

The central independent variable measures the level of electoral support for any of the right-wing extremist parties during the national (2009) and EP election (2009) *prior* to the existence of a successful populist right party within the German party system. These parties include the 'major' right-wing extremist parties NPD, DVU, Republikaner, and some smaller right-wing extremist parties that have only occasionally received public attention (Die Rechte, Offensive D, Bueso). These parties have their roots in different phases of the history of German right-wing extremism, shaping the different nuances of their programmatic outlook on society [e.g., @Betz.2003]. Yet, already by the late 1990s, the programmatic preferences of members and activists appeared to converge to a clear common programmatic core [@Lubbers.2001], leading some party members to even consider uniting forces [@Backer.2000, p.113]. To comprehensively capture the prevalent demand for radical right preferences within some local communities irrespective of the different party labels and different regional strongholds of the various parties [@Zimmermann.2003], I therefore consider the total vote share of all these parties that competed in the 2009 national and 2009 EP election. 



### Socio-demographic covariates at the municipal level

#### Degree of urbanisation

I measure the degree of urbanization of a municipality by relying on the Eurostat classification 'Degree of urbanisation (DEGURBA)'. According to this classification, which is based on the share of local population living in urban clusters and urban centres, three different types of area can be distinguished. First, cities (densely populated areas), second, towns and suburbs (intermediate density areas), and finally, rural areas (thinly populated areas). 


#### Local decline

I measure the socio-structural deprivation of a municipality by considering the difference between its population size and the population size during 2009 as a percentage share of the overall population size during 2009. Thus, positive values indicate that a municipality's population grew with respect to its size in 2009, while negative values indicate that more people moved away or died in a municipality than new citizens moved there or were born. The data is published on an annual basis (31.12) by the Federal Statistical Office as part of the 'List of Municipalities Information System (GV-ISys)'. As can be seen in Table \@ref(tab:summary-stats-western-germany) and Table \@ref(tab:summary-stats-eastern-germany), the relative change in the size of the population of municipalities located in Eastern Germany, on average, is negative, while the relative change in the size of the population of municipalities located in Western Germany since 2017 is positive.  

#### Population density

I measure the population density by the average number of citizens living in a municipality per square kilometre. The data on the territorial size of municipalities and their number of inhabitants is published on an annual basis (31.12) by the Federal Statistical Office as part of the 'List of Municipalities Information System (GV-ISys)'.


# Descriptive statistics

```{r dataframes-summary-stats}

minmax <- function(x) {
  (
    paste0(
      "[",
      round(min(x, na.rm = TRUE), digits = 2),
      ", ",
      round(max(x, na.rm = TRUE), digits = 2),
      "]"
    )
  )
}


fnlist <- function(x) {
  (
    list(x)
  )
}

summary_stats_west <- afd_spatial %>%
  filter(east == "West Germany") %>%
  as_tibble() %>%
  select(-geometry) %>%
  mutate(year_group = case_when(
    year_num == 2013 | year_num == 2014 ~ "2013/2014",
    TRUE ~ "2017/2019"
  )) %>%
  ungroup() %>%
  select(year_group, election_type,
    `AfD Vote Share` = vote_share,
    `Extreme Right (2009)` = rr_vote_share_2009,
    `Invalid Share (2009)` = invalid_share_2009,
    `Abstention Rate (2009)` = abstention_share_2009,
    `Rural area` = population_thin,
    `Small urban area` = population_intermediate,
    `Population change since 2009` = pop_change_since_2009,
    `Population density (1000/km$^2$)` = population_density,
    `Area (km$^2$)` = area,
    `Eligible Voters (1000)` = eligible
  ) %>%
  group_by(election_type, year_group) %>%
  summarise(across(everything(),
    list(
      mean = mean,
      sd = sd,
      minmax = minmax,
      list = fnlist
    ),
    .names = "{.col}_{.fn}"
  )) %>%
  pivot_longer(-c(election_type, year_group),
    names_to = c("Variable", ".value"), names_sep = "_"
  ) %>%
  pivot_wider(
    id_cols = c(election_type, Variable),
    names_from = year_group,
    values_from = c(mean, sd, minmax, list)
  ) %>%
  ungroup() %>%
  mutate(election_type = case_when(
    election_type == "EP" ~ "EP election",
    election_type == "Parliament" ~ "National election"
  )) %>%
  arrange(desc(election_type))




summary_stats_east <- afd_spatial %>%
  filter(east == "East Germany") %>%
  as_tibble() %>%
  select(-geometry) %>%
  mutate(year_group = case_when(
    year_num == 2013 | year_num == 2014 ~ "2013/2014",
    TRUE ~ "2017/2019"
  )) %>%
  ungroup() %>%
  select(year_group, election_type,
    `AfD Vote Share` = vote_share,
    `Extreme Right (2009)` = rr_vote_share_2009,
    `Invalid Share (2009)` = invalid_share_2009,
    `Abstention Rate (2009)` = abstention_share_2009,
    `Rural area` = population_thin,
    `Small urban area` = population_intermediate,
    `Population change since 2009` = pop_change_since_2009,
    `Population density (1000/km$^2$)` = population_density,
    `Area (km$^2$)` = area,
    `Eligible Voters (1000)` = eligible
  ) %>%
  group_by(election_type, year_group) %>%
  summarise(across(everything(),
    list(
      mean = mean,
      sd = sd,
      minmax = minmax,
      list = fnlist
    ),
    .names = "{.col}_{.fn}"
  )) %>%
  pivot_longer(-c(election_type, year_group),
    names_to = c("Variable", ".value"), names_sep = "_"
  ) %>%
  pivot_wider(
    id_cols = c(election_type, Variable),
    names_from = year_group,
    values_from = c(mean, sd, minmax, list)
  ) %>%
  ungroup() %>%
  mutate(election_type = case_when(
    election_type == "EP" ~ "EP election",
    election_type == "Parliament" ~ "National election"
  )) %>%
  arrange(desc(election_type))
```


```{r summary-stats-western-germany}

kable(summary_stats_west %>%
  select(-matches("list")) %>%
  ungroup() %>%
  # create empty columns for the plots
  mutate(
    `hist_2013/2014` = " ",
    `hist_2017/2019` = " ",
    `box_2013/2014` = " ",
    `box_2017/2019` = " "
  ) %>%
  # order the columns correctly
  select(
    c("Variable"),
    matches("2013/2014"),
    matches("2017/2019")
  ),
digits = 2,
col.names = c(
  "",
  "Mean", "SD", "[Min, Max]", " ", " ",
  "Mean", "SD", "[Min, Max]", " ", " "
),
booktabs = TRUE,
escape = FALSE,
caption = "Summary statistics (West Germany)"
) %>%
  # add the histogram and the boxplots to the table (empty columns needed)
  column_spec(5, image = spec_hist(summary_stats_west$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(6, image = spec_boxplot(summary_stats_west$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(10, image = spec_hist(summary_stats_west$`list_2017/2019`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(11, image = spec_boxplot(summary_stats_west$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  # group the table by national and EP election
  pack_rows(index = rev(table(summary_stats_west$election_type))) %>%
  kableExtra::kable_styling(bootstrap_options = "striped") %>%
  # column labels Year Groups
  add_header_above(c(
    " " = 1,
    "2013/2014" = 5,
    "2017/2019" = 5
  )) %>%
  add_header_above(c(
    " " = 1,
    "West Germany" = 10
  ))
```


```{r summary-stats-eastern-germany}

kable(summary_stats_east %>%
  select(-matches("list")) %>%
  ungroup() %>%
  # create empty columns for the plots
  mutate(
    `hist_2013/2014` = " ",
    `hist_2017/2019` = " ",
    `box_2013/2014` = " ",
    `box_2017/2019` = " "
  ) %>%
  # order the columns correctly
  select(
    c("Variable"),
    matches("2013/2014"),
    matches("2017/2019")
  ),
digits = 2,
col.names = c(
  "",
  "Mean", "SD", "[Min, Max]", " ", " ",
  "Mean", "SD", "[Min, Max]", " ", " "
),
booktabs = TRUE,
escape = FALSE,
caption = "Summary statistics (East Germany)"
) %>%
  # add the histogram and the boxplots to the table (empty columns needed)
  column_spec(5, image = spec_hist(summary_stats_east$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(6, image = spec_boxplot(summary_stats_east$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(10, image = spec_hist(summary_stats_east$`list_2017/2019`,
    same_lim = FALSE,
    width = 100
  )) %>%
  column_spec(11, image = spec_boxplot(summary_stats_east$`list_2013/2014`,
    same_lim = FALSE,
    width = 100
  )) %>%
  # group the table by national and EP election
  pack_rows(index = rev(table(summary_stats_east$election_type))) %>%
  kableExtra::kable_styling(bootstrap_options = "striped") %>%
  # column labels Year Groups
  add_header_above(c(
    " " = 1,
    "2013/2014" = 5,
    "2017/2019" = 5
  )) %>%
  add_header_above(c(
    " " = 1,
    "East Germany" = 10
  ))
```


# Spatial dependence 


```{r global-moranI-stat-residuals}

afd_spatial_nest <- afd_spatial_nest %>%
  mutate( # compute the moran I stat of residuals
    moranI_residuals = map2(
      lm_model,
      afd_spatial.lw,
      ~ lm.morantest(
        model = .x,
        listw = .y,
        alternative = "greater",
        zero.policy = T
      )
    ),
    # tidy moran I stat
    moranI_residuals = map(
      moranI_residuals,
      ~ tidy(.) %>%
        rename(
          moranstat = estimate1,
          expectation = estimate2,
          variance = estimate3
        )
    )
  )




afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  mutate( # compute the moran I stat of residuals
    moranI_residuals = map2(
      lm_model,
      afd_spatial.lw,
      ~ lm.morantest(
        model = .x,
        listw = .y,
        alternative = "greater",
        zero.policy = T
      )
    ),
    # tidy moran I stat
    moranI_residuals = map(
      moranI_residuals,
      ~ tidy(.) %>%
        rename(
          moranstat = estimate1,
          expectation = estimate2,
          variance = estimate3
        )
    )
  )
```

```{r table-moranI}

# prepare a table
moran_table_residuals <- afd_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    moranI_residuals
  ) %>%
  mutate(moranI_residuals_stat = map(
    moranI_residuals,
    ~ round(.$moranstat, digits = 3)
  )) %>%
  mutate(moranI_residuals_pvalue = map(
    moranI_residuals,
    ~ round(.$p.value, digits = 10)
  )) %>%
  mutate(year = lubridate::year(election_date)) %>%
  ungroup() %>%
  select(-moranI_residuals, -election_date, -moranI_residuals_pvalue) %>%
  arrange(desc(east), desc(election_type), year) %>%
  mutate(moranI_residuals_stat = as.numeric(unlist(moranI_residuals_stat))) %>%
  pivot_wider(
    names_from = c(east),
    values_from = moranI_residuals_stat
  ) %>%
  rename(
    east_moranI_residuals_afd = `East Germany`,
    west_moranI_residuals_afd = `West Germany`
  )


moran_table_growth_residuals <- afd_growth_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    moranI_residuals
  ) %>%
  mutate(moranI_residuals_stat = map(
    moranI_residuals,
    ~ round(.$moranstat, digits = 3)
  )) %>%
  mutate(moranI_residuals_pvalue = map(
    moranI_residuals,
    ~ round(.$p.value, digits = 10)
  )) %>%
  mutate(year = lubridate::year(election_date)) %>%
  ungroup() %>%
  select(-moranI_residuals, -election_date, -moranI_residuals_pvalue) %>%
  arrange(desc(east), desc(election_type), year) %>%
  mutate(moranI_residuals_stat = as.numeric(unlist(moranI_residuals_stat))) %>%
  pivot_wider(
    names_from = c(east),
    values_from = moranI_residuals_stat
  ) %>%
  rename(
    east_moranI_residuals_afd_growth = `East Germany`,
    west_moranI_residuals_afd_growth = `West Germany`
  )


moran_table <- full_join(
  moran_table_residuals,
  moran_table_growth_residuals,
  by = c("year", "election_type")
) %>%
  select(election_type, year, starts_with("west"), starts_with("east"))


options(knitr.kable.NA = "")
kable(moran_table,
  booktabs = T,
  longtable = T,
  escape = FALSE,
  col.names = c("Election", "Year", "AfD", "$\\Delta$ AfD", "AfD", "$\\Delta$ AfD"),
  caption = "Global Moran's I Statistic of the OLS Residuals"
) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 2,
    "West Germany" = 2,
    "East Germany" = 2
  )) %>%
  kableExtra::footnote(
    general_title = "",
    general = "Residuals from OLS regression including county-fixed effects and covariates.",
    threeparttable = TRUE,
    footnote_as_chunk = T
  ) %>% 
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"))


minimum_moran_I_with_fixed_effects <- round(
  min(moran_table$west_moranI_residuals_afd_growth,
    moran_table$west_moranI_residuals_afd,
    moran_table$east_moranI_residuals_afd_growth,
    moran_table$east_moranI_residuals_afd,
    na.rm = T
  ),
  digits = 2
)


maximum_moran_I_with_fixed_effects <- round(
  max(moran_table$west_moranI_residuals_afd_growth,
    moran_table$west_moranI_residuals_afd,
    moran_table$east_moranI_residuals_afd_growth,
    moran_table$east_moranI_residuals_afd,
    na.rm = T
  ),
  digits = 2
)
```


Table \@ref(tab:table-moranI) reports the global Moran I's test statistic for the residuals of a simple OLS regression model that does not take any spatial dependence into account. While the degree of the spatial dependence in the data after the inclusion of county-fixed-effects and municipal level covariates is moderate with values ranging from `r min(moran_table$west_moranI_residuals_afd_growth, moran_table$west_moranI_residuals_afd, moran_table$east_moranI_residuals_afd_growth, moran_table$east_moranI_residuals_afd, na.rm=T)` to `r max(moran_table$west_moranI_residuals_afd_growth, moran_table$west_moranI_residuals_afd, moran_table$east_moranI_residuals_afd_growth, moran_table$east_moranI_residuals_afd, na.rm=T)``, these values are still highly statistically significant. Thus, they point to a persisting spatial dependence in the multivariate model that might be rooted in spatial lag and/or spatial error dependence. 



## Spatial lag and spatial error dependence 

I rely on the Lagrange Multiplier test to determine whether the spatial dependence is a result of spatial lag and/or spatial error correlation (see Table \@ref(tab:lm-test-for-spatial-dependence) and Table \@ref(tab:lm-test-for-growth-spatial-dependence)). The results of these tests point to the presence of spatial error dependence in the absence of any spatial lag dependence. 


```{r lm-test-for-spatial-dependence}

afd_spatial_nest <- afd_spatial_nest %>%
  mutate(
    lm_LMtest = map2(
      lm_model,
      afd_spatial.lw,
      ~ lm.LMtests(
        .x,
        .y,
        test = c("LMlag", "LMerr", "RLMlag", "RLMerr"),
        zero.policy = T
      )
    ),
    tibble_lm_LMtest = map(
      lm_LMtest,
      ~ summary(.) %>%
        pluck("results") %>%
        mutate(
          stat = unlist(statistic),
          test = names(statistic)
        ) %>%
        select(-c(
          statistic,
          # parameter is simply degrees of freedom, always 1 in LMtest
          parameter
        ))
    )
  )

# prepare a table
lmtest_table_residuals <- afd_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    tibble_lm_LMtest
  ) %>%
  mutate(tibble_lm_LMtest_wide = map(
    tibble_lm_LMtest,
    ~ pivot_wider(.,
      names_from = c(test),
      values_from = c(-test)
    )
  )) %>%
  select(-tibble_lm_LMtest) %>%
  unnest(tibble_lm_LMtest_wide) %>%
  mutate(election_date = year(election_date))


kable(lmtest_table_residuals %>%
  select(
    election_date,
    election_type,
    east,
    stat_LMlag, p.value_LMlag,
    stat_LMerr, p.value_LMerr
  ) %>%
  arrange(desc(east), desc(election_type), election_date),
booktabs = T,
col.names = c(
  "Election", "Year", "Region",
  "Test", "p value",
  "Test", "p value"
),
digits = 4,
caption = "Diagnostics for Spatial Dependence in OLS Model of AfD Vote Share"
) %>%
  kableExtra::kable_styling(bootstrap_options = c("striped")) %>%
  kableExtra::add_header_above(c(" " = 3, "LM Lag" = 2, "LM Error" = 2))
```


I rely on Lagrange Multiplier (LM) diagnostics for spatial dependence to assess which modeling strategy is appropriate to model the remaining spatial dependence in the data. I follow the decision rule proposed by @Anselin.2005 [p.198f.] and first report the results of the LM lag and LM error test, respectively.  

The results of the tests are reported in Table \@ref(tab:lm-test-for-spatial-dependence). The LM test for spatial lag dependence results in values very close to zero across all elections, leading to a rejection of the null. The LM test for spatial error dependence, in contrast, results in much larger values that are also statistically significant. 


```{r lm-test-for-growth-spatial-dependence}

afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  mutate(
    lm_LMtest = map2(
      lm_model,
      afd_spatial.lw,
      ~ lm.LMtests(
        .x,
        .y,
        test = c("LMlag", "LMerr", "RLMlag", "RLMerr"),
        zero.policy = T
      )
    ),
    tibble_lm_LMtest = map(
      lm_LMtest,
      ~ summary(.) %>%
        pluck("results") %>%
        mutate(
          stat = unlist(statistic),
          test = names(statistic)
        ) %>%
        select(-c(
          statistic,
          parameter
        ))
    )
  )

# prepare a table
lmtest_growth_table_residuals <- afd_growth_spatial_nest %>%
  select(
    election_date,
    election_type,
    east,
    tibble_lm_LMtest
  ) %>%
  mutate(tibble_lm_LMtest_wide = map(
    tibble_lm_LMtest,
    ~ pivot_wider(.,
      names_from = c(test),
      values_from = c(-test)
    )
  )) %>%
  select(-tibble_lm_LMtest) %>%
  unnest(tibble_lm_LMtest_wide) %>%
  mutate(election_date = year(election_date))


kable(lmtest_growth_table_residuals %>%
  select(
    election_date,
    election_type,
    east,
    stat_LMlag, p.value_LMlag,
    stat_LMerr, p.value_LMerr
  ) %>%
  arrange(desc(east), desc(election_type), election_date),
booktabs = T,
col.names = c(
  "Election", "Year", "Region",
  "Test", "p value",
  "Test", "p value"
),
digits = 4,
caption = "Diagnostics for Spatial Dependence in OLS Model of $\\Delta$ AfD Vote Share"
) %>%
  kableExtra::kable_styling(bootstrap_options = c("striped")) %>%
  kableExtra::add_header_above(c(" " = 3, "LM Lag" = 2, "LM Error" = 2))
```



# Analyses

I rely on a county-fixed effects design to isolate the effect of latent radical right demand on the electoral success of the AfD from any structural variation between municipalities. On average, the `r afd_spatial %>% group_by(county_id) %>% slice(1) %>% nrow()` counties in the data cover a small area of only 1139km$^2$. 

I present spatial simultaneous autoregressive error models by maximum likelihood estimation, relying on a queen-style contiguous neighbours definition, in which all polygons contiguous to a municipality $i$ are considered neighbours [@Anselin.1988, p.18]. 

## Model estimation 

The following code chunks estimate these spatial simultaneous autoregressive error models. They are computationally very intense and I have conducted all analyses by relying on [Future's parallel processing capabilities](https://en.wikipedia.org/wiki/Futures_and_promises). Please make sure your machine has sufficient computational power before running the code and changing the chunk options to `eval = TRUE`.

```{r estimate-the-sarslm-model-2009, eval=FALSE}

library(furrr)
plan(multisession, workers = 18)

## 2009 RR vote

covariates <- c(
  "population_thin",
  "population_intermediate",
  "pop_change_since_2009",
  "population_density",
  "area",
  "invalid_share_2009",
  "abstention_share_2009"
)




tic()
# most parsimonious dataset for the spatial sem
afd_spatial_nest_sem <- afd_spatial_nest %>%
  select(election_type, east, election_date, data_std, afd_spatial.lw) %>%
  mutate(data_std = map(
    data_std,
    ~ ungroup(.) %>%
      as_tibble(.) %>%
      select(-geometry)
  )) %>%
  ungroup()



afd_spatial_nest_sem <- afd_spatial_nest_sem %>%
  mutate(model_eq = map(
    election_type,
    ~ model_eq(election_type = .x)
  )) %>%
  # estimate the sem model
  mutate(
    sem_model =
      future_pmap(
        list(
          data_std,
          afd_spatial.lw,
          model_eq
        ),
        ~ spatialreg::errorsarlm(
          data = ..1,
          listw = ..2,
          formula = ..3,
          zero.policy = TRUE
        )
      )
  )
toc()


# save selected vars for smaller total dataset
afd_spatial_nest_sem <- afd_spatial_nest_sem %>%
  ungroup() %>%
  dplyr::select(election_date, east, sem_model)
save(afd_spatial_nest_sem,
  file = "afd_spatial_nest_sem.RData"
)




tic()
afd_growth_spatial_nest_sem <- afd_growth_spatial_nest %>%
  select(election_type, east, election_date, data_std, afd_spatial.lw) %>%
  mutate(data_std = map(
    data_std,
    ~ ungroup(.) %>%
      as_tibble(.) %>%
      select(-geometry)
  )) %>%
  ungroup()



afd_growth_spatial_nest_sem <- afd_growth_spatial_nest_sem %>%
  mutate(model_growth_eq = map(
    election_type,
    ~ model_growth_eq(.x)
  )) %>%
  # estimate the sem model
  mutate(
    sem_model =
      future_pmap(
        list(
          data_std,
          afd_spatial.lw,
          model_growth_eq
        ),
        ~ spatialreg::errorsarlm(
          data = ..1,
          listw = ..2,
          formula = ..3,
          zero.policy = TRUE
        )
      )
  )
toc()


# save selected vars for smaller total dataset
afd_growth_spatial_nest_sem <- afd_growth_spatial_nest_sem %>%
  ungroup() %>%
  dplyr::select(election_date, east, sem_model)
save(afd_growth_spatial_nest_sem,
  file = "afd_growth_spatial_nest_sem.RData"
)
```


```{r estimate-the-sarslm-model-2005, eval=FALSE}

library(furrr)
plan(multisession, workers = 18)


covariates <- c(
  "population_thin",
  "population_intermediate",
  "pop_change_since_2005",
  "population_density",
  "area",
  "invalid_share_2005",
  "abstention_share_2005"
)

# model equation
model_eq <- paste0(
  "vote_share ~ rr_vote_share_2005 + ",
  paste(covariates, collapse = " + "),
  " + as.factor(afd_candidate)",
  " + as.factor(county_id)"
)


# model equation
model_growth_eq <- paste0(
  "vote_delta ~ rr_vote_share_2005 + ",
  paste(covariates, collapse = " + "),
  " + as.factor(afd_candidate)",
  " + as.factor(county_id)"
)




tic()
afd_spatial_nest_05_sem <- afd_spatial_nest %>%
  filter(election_type == "Parliament") %>%
  select(election_type, east, election_date, data_std, afd_spatial.lw) %>%
  mutate(data_std = map(
    data_std,
    ~ ungroup(.) %>%
      as_tibble(.) %>%
      select(-geometry)
  )) %>%
  ungroup()


afd_spatial_nest_05_sem <- afd_spatial_nest_05_sem %>%
  # estimate the sem model
  mutate(
    sem_model =
      future_pmap(
        list(
          data_std,
          afd_spatial.lw
        ),
        ~ spatialreg::errorsarlm(
          data = ..1,
          listw = ..2,
          model_eq,
          zero.policy = TRUE
        )
      )
  )
toc()


# save selected vars for smaller total dataset
afd_spatial_nest_05_sem <- afd_spatial_nest_05_sem %>%
  ungroup() %>%
  dplyr::select(election_date, east, sem_model)
save(afd_spatial_nest_05_sem,
  file = "afd_spatial_nest_05_sem.RData"
)



tic()
afd_growth_spatial_nest_05_sem <- afd_growth_spatial_nest %>%
  filter(election_type == "Parliament") %>%
  select(election_type, east, election_date, data_std, afd_spatial.lw) %>%
  mutate(data_std = map(
    data_std,
    ~ ungroup(.) %>%
      as_tibble(.) %>%
      select(-geometry)
  )) %>%
  ungroup()



afd_growth_spatial_nest_05_sem <- afd_growth_spatial_nest_05_sem %>%
  # estimate the sem model
  mutate(
    sem_model =
      future_pmap(
        list(
          data_std,
          afd_spatial.lw
        ),
        ~ spatialreg::errorsarlm(
          data = ..1,
          listw = ..2,
          model_growth_eq,
          zero.policy = TRUE
        )
      )
  )
toc()

# save selected vars for smaller total dataset
afd_growth_spatial_nest_05_sem <- afd_growth_spatial_nest_05_sem %>%
  ungroup() %>%
  dplyr::select(election_date, east, sem_model)
save(afd_growth_spatial_nest_05_sem,
  file = "afd_growth_spatial_nest_05_sem.RData"
)
```




## Latent radical right potential hypothesis (H1)

```{r load-the-sem-data}

unzip(zipfile = "./data/afd_spatial_sem_models.zip", 
      overwrite = T)


load("afd_spatial_nest_sem.RData")

afd_spatial_nest <- afd_spatial_nest %>%
  left_join(.,
    afd_spatial_nest_sem,
    by = c("election_date", "east")
  )

rm(afd_spatial_nest_sem)
```



```{r regression-h1}

# arrange for regression table.
# present results by two dimensions
# A) West-East Germany
# B) EP-Parliamentary Elections

afd_spatial_nest <- afd_spatial_nest %>%
  arrange(
    desc(east),
    desc(election_type),
    election_date
  )

f <- function(x) format(round(x, 2))
gm <- list(
  list("raw" = "r.squared", "clean" = "R$^2$", "fmt" = f),
  list("raw" = "nobs", "clean" = "Num.Obs.", "fmt" = f)
)

cm <- c(
  "rr_vote_share_2009" = "Extreme Right (2009)",
  "invalid_share_2009" = "Invalid Share (2009)",
  "abstention_share_2009" = "Abstention Rate (2009)",
  "population_thin" = "Rural area",
  "population_intermediate" = "Small urban area",
  "pop_change_since_2009" = "Population change since 2009",
  "population_density" = "Population density (1000/km$^2$)",
  "area" = "Area (km$^2$)",
  "as.factor(afd_candidate)1" = "Resident AfD candidate",
  "(Intercept)" = "Intercept",
  "lambda" = "$\\lambda$"
)


# change the names of the sem model to the year of the election, i.e. the lowest dimension in the kableExtra regression table
names(afd_spatial_nest$sem_model) <- lubridate::year(afd_spatial_nest$election_date)


# add additional information for the regression table
model_id_chr <- c(paste0(
  year(afd_spatial_nest$election_date),
  paste0(stringr::str_sub(afd_spatial_nest$election_type, 1, 4)),
  paste0(afd_spatial_nest$east)
))
countyFE_N <- c(
  "Number of Counties",
  map(
    afd_spatial_nest$data,
    ~ length(unique(.$county_id)) %>%
      as.character()
  )
) %>%
  set_names(., c("term", model_id_chr))

rows <- tibble(
  model_id = model_id_chr,
  check_countyFE = "$\\checkmark$",
  term = "County-Fixed Effects"
) %>%
  pivot_wider(
    id_cols = term,
    values_from = c("check_countyFE"),
    names_from = "model_id"
  ) %>%
  bind_rows(
    .,
    countyFE_N
  )


attr(rows, "position") <- c(2 * length(cm) + 1, 2 * length(cm) + 2)
names(rows) <- c("term", names(afd_spatial_nest$sem_model))


modelsummary(afd_spatial_nest$sem_model,
  add_rows = rows,
  stars = TRUE,
  fmt = 2,
  title = "Support for the AfD as a function of local prevalence of deep-seated nativism",
  coef_map = cm,
  gof_map = gm,
  gof_omit = "DF|Deviance|BIC|Log.Lik.|AIC",
  escape = FALSE,
  output = "kableExtra"
) %>%
  # column labels second dimension: Parliament-EP Elections
  add_header_above(c(
    " " = 1,
    "National Election" = 2,
    "EP Election" = 2,
    "National Election" = 2,
    "EP Election" = 2
  )) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 1,
    "West Germany" = 4,
    "East Germany" = 4
  )) %>%
  # footnote
  add_footnote("Spatial simultaneous autoregressive error model by maximum likelihood estimation.",
    notation = "none"
  )
```

I first report the results from models estimating the level of populist right success to assess the *Latent Radical Right Potential Hypothesis*. All continuous variables are standardised with respect to their *region-specific* means to ensure that the average one-unit increase expressed in the coefficients represents a meaningful unit of change for all observations in the dataset. Across the different regions, there have been marked differences in both average levels and the variation in the level and the growth of populist right AfD success (see Figure \@ref(fig:variation-in-afd-growth)). Therefore, it appears critical to standardise the variable to a zero mean and unit standard deviation within each state to make sure that the coefficient estimates (one unit increases) reflect relevant quantities within the state-specific data that can be compared across states. 

## Figure A1: Variation in the AfD’s mean vote shares and changes in vote shares across different states.

```{r variation-in-afd-growth, out.width="100%", fig.cap="Variation in the AfD's mean vote shares and changes in vote shares across different states. Light shading indicates Eastern German states. Pointranges indicate the standard deviation of the (changes in) the AfD's electoral performance.", fig.height=6, fig.retina=8}

# create one tibble that contains information on state-specific afd growth and baseline levels in 2013
plot_afd_states <- bind_rows(
  # afd growth
  afd_growth_spatial %>%
    ungroup() %>%
    as_tibble() %>%
    # deselect the geometry column for efficiency
    select(-geometry) %>%
    group_by(election_type, election_date, state_name, east) %>%
    dplyr::summarise(
      mean_vote = weighted.mean(vote_delta,
        weights = eligible / sum(eligible, na.rm = T),
        na.rm = T
      ),
      sd_vote = sd(vote_delta,
        na.rm = T
      )
    ) %>%
    mutate(measure = "Delta Vote Share"),
  # afd levels
  afd_spatial %>%
    ungroup() %>%
    as_tibble() %>%
    # deselect the geometry column for efficiency
    select(-geometry) %>%
    group_by(election_type, election_date, state_name, east) %>%
    dplyr::summarise(
      mean_vote = weighted.mean(vote_share,
        weights = eligible / sum(eligible, na.rm = T),
        na.rm = T
      ),
      sd_vote = sd(vote_share,
        na.rm = T
      )
    ) %>%
    mutate(measure = "Vote Share")
)



plot_afd_states %>%
  arrange(desc(state_name)) %>%
  mutate(
    east =
      case_when(
        east == "East Germany" ~ 1,
        TRUE ~ 0
      )
  ) %>%
  mutate(
    election_type_year =
      case_when(
        election_type == "Parliament" & election_date == ymd("2013-09-22") ~ "2013 - Parliament",
        election_type == "EP" & election_date == ymd("2014-05-25") ~ "2014 - EP",
        election_type == "Parliament" & election_date == ymd("2017-09-24") ~ "2017 - Parliament",
        election_type == "EP" & election_date == ymd("2019-05-26") ~ "2019 - EP",
      )
  ) %>%
  # start plotting
  ggplot(aes(
    y = state_name,
    x = mean_vote,
    color = as.factor(election_type),
    alpha = as.numeric(east),
    shape = forcats::fct_rev(election_type_year)
  )) +
  geom_pointrange(
    position = position_dodge(width = 0.8),
    aes(
      y = forcats::fct_rev(state_name),
      x = mean_vote,
      xmin = mean_vote - (sd_vote),
      xmax = mean_vote + (sd_vote)
    )
  ) +
  geom_hline(yintercept = 0, linetype = "dotdash") +
  scale_color_discrete_divergingx(guide = "none") +
  scale_alpha_continuous(range = c(1, 0.5), guide = "none") +
  # scale_color_grey(start = 0.8, end = 0.4, guide = FALSE) +
  scale_shape_discrete(
    guide = guide_legend(reverse = TRUE),
    name = "Election"
  ) +
  labs(
    y = "",
    x = ""
  ) +
  facet_wrap(facets = ~ forcats::fct_rev(measure))
```


Table \@ref(tab:regression-h1) presents the results of the models predicting the electoral success of the populist right AfD across all elections as a function of the extreme right's support during the elections prior to the existence of the AfD. 


## Multiplier hypothesis (H2)

I next turn to assess the H2 (*Multiplier Hypothesis*). Table \@ref(tab:regression-h2) presents the results of the models assessing this pattern. Columns 1 and 2 refer to municipalities located in Western Germany, while columns 3 and 4 refer to municipalities located in Eastern Germany. Figure \@ref(fig:visualising-effect-sizes) shows the average sizes of this effect in percentage points rather than region-specific standard deviations (dark shading) and the respective state-specific effect sizes across the different regions (shown in light shading). The results support H2 (*Multiplier Hypothesis*). 

```{r load-the-sem-growth-data}

load("afd_growth_spatial_nest_sem.RData")

afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  left_join(.,
    afd_growth_spatial_nest_sem,
    by = c("election_date", "east")
  )

rm(afd_growth_spatial_nest_sem)
```


```{r regression-h2}

# arrange for regression table.
# present results by two dimensions
# A) West-East Germany
# B) EP-Parliamentary Elections
afd_growth_spatial_nest <- afd_growth_spatial_nest %>%
  arrange(desc(east), desc(election_type), election_date)

# create regression table

cm <- c(
  "rr_vote_share_2009" = "Extreme Right (2009)",
  "invalid_share_2009" = "Invalid Share (2009)",
  "abstention_share_2009" = "Abstention Rate (2009)",
  "population_thin" = "Rural area",
  "population_intermediate" = "Small urban area",
  "pop_change_since_2009" = "Pop. change since 2009",
  "population_density" = "Pop. density (1000/km$^2$)",
  "area" = "Area (km$^2$)",
  "eligible" = "Eligible Voters (1000)",
  "as.factor(afd_candidate)1" = "Resident AfD candidate",
  "(Intercept)" = "Intercept",
  "lambda" = "$\\lambda$"
)


# change the names of the sem model to the year of the election, i.e. the lowest dimension in the kableExtra regression table
names(afd_growth_spatial_nest$sem_model) <- lubridate::year(afd_growth_spatial_nest$election_date)


# add additional information for the regression table
model_id_chr <- c(paste0(
  year(afd_growth_spatial_nest$election_date),
  paste0(stringr::str_sub(afd_growth_spatial_nest$election_type, 1, 4)),
  paste0(afd_growth_spatial_nest$east)
))
countyFE_N <- c(
  "Number of Counties",
  map(
    afd_growth_spatial_nest$data,
    ~ length(unique(.$county_id)) %>%
      as.character()
  )
) %>%
  set_names(., c("term", model_id_chr))

rows <- tibble(
  model_id = model_id_chr,
  check_countyFE = "$\\checkmark$",
  term = "County-Fixed Effects"
) %>%
  pivot_wider(
    id_cols = term,
    values_from = c("check_countyFE"),
    names_from = "model_id"
  ) %>%
  bind_rows(
    .,
    countyFE_N
  )


attr(rows, "position") <- c(2 * length(cm) + 1, 2 * length(cm) + 2)
names(rows) <- c("term", names(afd_growth_spatial_nest$sem_model))


modelsummary(afd_growth_spatial_nest$sem_model,
  add_rows = rows,
  stars = TRUE,
  fmt = 2,
  title = "Increase in support for the AfD as a function of local prevalence of deep-seated nativism",
  coef_map = cm,
  gof_map = gm,
  gof_omit = "DF|Deviance|BIC|Log.Lik.",
  escape = FALSE,
  output = "kableExtra"
) %>%
  # column labels second dimension: Parliament-EP Elections
  add_header_above(c(
    " " = 1,
    "$\\Delta$ National Election" = 1,
    "$\\Delta$ EP Election" = 1,
    "$\\Delta$ National Election" = 1,
    "$\\Delta$ EP Election" = 1
  ),
  escape = FALSE
  ) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 1,
    "West Germany" = 2,
    "East Germany" = 2
  )) %>%
  # footnote
  add_footnote("Spatial simultaneous autoregressive error model by maximum likelihood estimation. All continuous variables are standardised.",
    notation = "none"
  ) 
```



```{r estimate-effect-sizes}

average_sd_growth_states <- afd_growth_spatial_nest %>%
  select(election_type, east, election_date, data) %>%
  unnest(data) %>%
  group_by(election_date, year, state_name, east, election_type) %>%
  summarise(
    state_sd = sd(vote_delta),
    state_sd_rr = sd(rr_vote_share_2009),
    sum_eligibles = sum(eligible)
  ) %>%
  # add average effect sizes/estimates
  left_join(.,
    afd_growth_spatial_nest %>%
      select(sem_model, election_type, east, election_date) %>%
      mutate(sem_model = map(sem_model, ~ tidy(.) %>%
        select(term, estimate, std.error) %>%
        filter(term == "rr_vote_share_2009"))) %>%
      unnest(sem_model),
    by = c("east", "election_type", "election_date")
  ) %>%
  # create variable percentage point increases
  mutate(percentage_point_changes = estimate * state_sd)


average_sd_growth_east <- afd_growth_spatial_nest %>%
  select(election_type, east, election_date, data) %>%
  unnest(data) %>%
  select(-geometry) %>%
  # add the state average sd
  left_join(.,
    average_sd_growth_states %>%
      select(-percentage_point_changes),
    by = c("east", "election_type", "election_date", "state_name", "year")
  ) %>%
  # the percentage point increase is a product of each state's specific sd and the four estimates for east/west EP/national
  mutate(percentage_point_changes = estimate * state_sd) %>%
  group_by(east, election_type, election_date) %>%
  # calculate weighted mean of the increase
  summarise(
    percentage_point_changes = weighted.mean(percentage_point_changes,
      w = eligible / sum(eligible)
    ),
    sum_eligibles = sum(eligible)
  ) %>%
  mutate(state_name = east)
```



```{r visualising-effect-sizes, fig.cap="Effect of extreme-right support (2009) on growth of populist right success in local communities. Darker shading indicates the overall average percentage point increase while lighter shading indicates the respective effect sizes for the different regions.", out.width="70%"}

# bind the data to make sure the position_dodge works simultaneously for all data in a single geom
ggplot(
  data = average_sd_growth_states %>%
    mutate(state_obs = TRUE) %>%
    bind_rows(
      .,
      average_sd_growth_east %>%
        mutate(state_obs = FALSE)
    ),
  aes(
    x = forcats::fct_rev(east),
    y = percentage_point_changes
  )
) +
  geom_point(aes(
    size = sum_eligibles,
    fill = as.factor(election_type),
    alpha = if_else(is.na(state_sd), 1, 0.4)
  ),
  color = "black",
  position = position_dodge(width = 0.5),
  shape = 21
  ) +
  # no scale for the size
  scale_size_continuous(guide = "none") +
  # scale for alpha
  scale_alpha_continuous(range = c(0.4, 1), guide = "none") +
  # filling of the geoms
  colorspace::scale_fill_discrete_divergingx(name = "Election") +
  # extend the y axis to include 0
  scale_y_continuous(limits = c(0, 1.8)) +
  labs(
    x = "",
    y = expression(paste(Delta, " Increase AfD"))
  ) +
  # increase the size of the points shown in the legend
  guides(fill = guide_legend(override.aes = list(size = 3))) +
  theme(
    legend.position = c(0.1, 0.85),
    legend.background = element_rect(
      fill = "white",
      color = "grey50"
    )
  )
```




# Other analyses

## Figure 1: Public ignorance about the programmatic positions of the AfD

Figure \@ref(fig:afd-dontknow-trend) shows the proportion of individuals who did not know where to position the AfD on a left-right scale ranging from 0 to 10. Respondents had been interviewed in a series of cross-sectional surveys conducted over the period between 2013 and 2018. The data are taken from the German Longitudinal Election Study (the corresponding identifiers of the datasets are: ZA6827, ZA6832, ZA6820, ZA5738-44, ZA6821, ZA5700/01, ZA6800/01). The proportion shown in the graph refers to the share of respondents who indicated "do not know" when asked to position the populist right party on a left-right scale from 0 to 10. The dashed lines represent the national elections in 2013 and 2017 that are subjects of this study. The graph shows that the share of respondents who did not hold enough information about the programmatic profile of the young populist right party to confidently locate its position on a 0 to 10 scale decreased from more than 50% in late 2013 to less than 10% in 2018. 


```{r afd-dontknow-trend, fig.showtext=T, fig.retina=4, out.width="80%", fig.cap="Share of respondents who do not know where to position the populist radical right challenger AfD on a left-right scale strongly declined between 2013 and 2018."}

afd_dontknow_data <- read_csv(file = "./data/afd_dontknow.csv")

ggplot(
  data = afd_dontknow_data,
  aes(
    x = monthyear,
    y = afd_dontknow,
    size = number_respondents,
    color = eastwest
  )
) +
  geom_point() +
  labs(
    x = "",
    y = "",
    title = "Public ignorance about the programmatic positions of the AfD",
    subtitle = prettyNum(paste0(
      "N = ",
      afd_dontknow_data %>%
        ungroup() %>%
        filter(!is.na(afd_dontknow)) %>%
        summarise(all_respondents = sum(number_respondents)) %>%
        pull()
    ), big.mark = "."),
    caption = paste0("Data: GLES (ZA6827, ZA6832, ZA6820, ZA5738-44, ZA6821, ZA5700/01, ZA6800/01)")
  ) +
  # legend for the size of the points (total number of respondents)
  scale_size_continuous("N respondents") +
  # add some more ticks to the x axis showing the time
  scale_x_date(
    limits = c(ymd("2013-01-01"), NA),
    breaks = seq(ymd("2013-01-01"),
      ymd("2018-07-01"),
      by = "1 year"
    ),
    date_labels = "%Y"
  ) +
  scale_y_continuous(labels = scales::percent) +
  scale_color_brewer(
    name = "",
    palette = "Paired"
  ) +
  scale_size_continuous(guide = FALSE) +
  geom_vline(
    xintercept = dmy("24-09-2017"),
    linetype = 2
  ) +
  geom_vline(
    xintercept = dmy("27-09-2013"),
    linetype = 2
  )
```





## Alternative operationalisation of locally prevalent, pre-crises demand for nativist policies (electoral success of the extreme right in 2005) 

Table \@ref(tab:regression-h1-extreme-right-2005) shows that the results remain substantively the same when we operationalise a local community's latent radical right potential by the extreme-right vote share obtained during the national election 2005, which provides an alternative operationalisation of a pre-crises demand for nativist policies prevalent in some local communities. As the related data for the EP elections (2004) is not available on the municipal level, the main analysis is based on the electoral success of extreme-right parties in 2009 (national and EP election). 

```{r load-the-sem-data-05}

load("afd_spatial_nest_05_sem.RData")

afd_spatial_nest_05 <- afd_spatial_nest %>%
  filter(election_type == "Parliament") %>%
  select(-sem_model) %>%
  left_join(.,
    afd_spatial_nest_05_sem,
    by = c("election_date", "east")
  )

rm(afd_spatial_nest_05_sem)
```


```{r regression-h1-extreme-right-2005}

# arrange for regression table.
# present results by two dimensions
# A) West-East Germany
# B) EP-Parliamentary Elections

afd_spatial_nest_05 <- afd_spatial_nest_05 %>%
  arrange(desc(east), desc(election_type), election_date)

cm <- c(
  "rr_vote_share_2005" = "Extreme Right (2005)",
  "invalid_share_2005" = "Invalid Share (2005)",
  "abstention_share_2005" = "Abstention Rate (2005)",
  "population_thin" = "Rural area",
  "population_intermediate" = "Small urban area",
  "pop_change_since_2005" = "Population change since 2005",
  "population_density" = "Population density (1000/km$^2$)",
  "as.factor(afd_candidate)1" = "Resident AfD candidate",
  "area" = "Area (km$^2$)",
  "(Intercept)" = "Intercept",
  "lambda" = "$\\lambda$"
)


# change the names of the sem model to the year of the election, i.e. the lowest dimension in the kableExtra regression table
names(afd_spatial_nest_05$sem_model) <- lubridate::year(afd_spatial_nest_05$election_date)


# add additional information for the regression table
model_id_chr <- c(paste0(
  year(afd_spatial_nest_05$election_date),
  paste0(stringr::str_sub(afd_spatial_nest_05$election_type, 1, 4)),
  paste0(afd_spatial_nest_05$east)
))

countyFE_N <- c(
  "Number of Counties",
  map(
    afd_spatial_nest_05$data,
    ~ length(unique(.$county_id)) %>%
      as.character()
  )
) %>%
  set_names(., c("term", model_id_chr))

rows <- tibble(
  model_id = model_id_chr,
  check_countyFE = "$\\checkmark$",
  term = "County-Fixed Effects"
) %>%
  pivot_wider(
    id_cols = term,
    values_from = c("check_countyFE"),
    names_from = "model_id"
  ) %>%
  bind_rows(
    .,
    countyFE_N
  )


attr(rows, "position") <- c(2 * length(cm) + 1, 2 * length(cm) + 2)
names(rows) <- c("term", names(afd_spatial_nest_05$sem_model))


modelsummary(afd_spatial_nest_05$sem_model,
  add_rows = rows,
  stars = TRUE,
  fmt = 2,
  title = "Support for the AfD as a function of local prevalence of deep-seated nativism (2005)",
  coef_map = cm,
  gof_map = gm,
  gof_omit = "DF|Deviance|BIC|Log.Lik.|AIC",
  escape = FALSE,
  output = "kableExtra"
) %>%
  # column labels second dimension: Parliament-EP Elections
  add_header_above(c(
    " " = 1,
    "National Election" = 2,
    "National Election" = 2
  )) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 1,
    "West Germany" = 2,
    "East Germany" = 2
  )) %>%
  # footnote
  add_footnote("Spatial simultaneous autoregressive error model by ML estimation.",
    notation = "none"
  )
```


```{r load-the-sem-growth-data-05}

load("afd_growth_spatial_nest_05_sem.RData")

afd_growth_spatial_nest_05 <- afd_growth_spatial_nest %>%
  filter(election_type == "Parliament") %>%
  select(-sem_model) %>%
  left_join(.,
    afd_growth_spatial_nest_05_sem,
    by = c("election_date", "east")
  )

rm(afd_growth_spatial_nest_05_sem)
```


```{r regression-h2-extreme-right-2005}

# arrange for regression table.
# present results by two dimensions
# A) West-East Germany
# B) EP-Parliamentary Elections

afd_growth_spatial_nest_05 <- afd_growth_spatial_nest_05 %>%
  arrange(desc(east), desc(election_type), election_date)

# create regression table

cm <- c(
  "rr_vote_share_2005" = "Extreme Right (2005)",
  "invalid_share_2005" = "Invalid Share (2005)",
  "abstention_share_2005" = "Abstention Rate (2005)",
  "population_thin" = "Rural area",
  "population_intermediate" = "Small urban area",
  "pop_change_since_2005" = "Pop. change since 2005",
  "population_density" = "Pop. density (1000/km$^2$)",
  "area" = "Area (km$^2$)",
  "eligible" = "Eligible Voters (1000)",
  "as.factor(afd_candidate)1" = "Resident AfD candidate",
  "(Intercept)" = "Intercept",
  "lambda" = "$\\lambda$"
)


# change the names of the sem model to the year of the election, i.e. the lowest dimension in the kableExtra regression table
names(afd_growth_spatial_nest_05$sem_model) <- lubridate::year(afd_growth_spatial_nest_05$election_date)


# add additional information for the regression table
model_id_chr <- c(paste0(
  year(afd_growth_spatial_nest_05$election_date),
  paste0(stringr::str_sub(afd_growth_spatial_nest_05$election_type, 1, 4)),
  paste0(afd_growth_spatial_nest_05$east)
))
countyFE_N <- c(
  "Number of Counties",
  map(
    afd_growth_spatial_nest_05$data,
    ~ length(unique(.$county_id)) %>%
      as.character()
  )
) %>%
  set_names(., c("term", model_id_chr))

rows <- tibble(
  model_id = model_id_chr,
  check_countyFE = "$\\checkmark$",
  term = "County-Fixed Effects"
) %>%
  pivot_wider(
    id_cols = term,
    values_from = c("check_countyFE"),
    names_from = "model_id"
  ) %>%
  bind_rows(
    .,
    countyFE_N
  )


attr(rows, "position") <- c(2 * length(cm) + 1, 2 * length(cm) + 2)
names(rows) <- c("term", names(afd_growth_spatial_nest_05$sem_model))


modelsummary(afd_growth_spatial_nest_05$sem_model,
  add_rows = rows,
  stars = TRUE,
  fmt = 2,
  title = "Increase in support for the AfD as a function of local prevalence of deep-seated nativism (2005)",
  coef_map = cm,
  gof_map = gm,
  gof_omit = "DF|Deviance|BIC|Log.Lik.",
  escape = FALSE,
  output = "kableExtra"
) %>%
  # column labels second dimension: Parliament-EP Elections
  add_header_above(c(
    " " = 1,
    "$\\Delta$ National Election" = 1,
    "$\\Delta$ National Election" = 1
  ),
  escape = FALSE
  ) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 1,
    "West Germany" = 1,
    "East Germany" = 1
  )) %>%
  # footnote
  add_footnote("Spatial simultaneous autoregressive error model by ML estimation. All continuous variables are standardised.",
    notation = "none"
  ) 
```


## Local extreme-right networks and extreme-right success in 2005/2009

Table \@ref(tab:regression-table-extreme-right) demonstrates that the electoral success of the extreme right in 2009 is strongly associated with the local density of extreme-right activists. While there is no public data available on the local density of extreme-right organizations or their membership figures, we can approximate the local density of extreme-right activists with the help of data from the Federal Returning Officer that contains information on a total of 1199 extreme-right candidates that ran for office during the national election in 2005 and 2009. 


```{r regress-extremist-networks}

extreme_right_residences <- read_csv(file = "./data/extreme_right_activists.csv") %>%
  group_by(lat, long) %>%
  summarise(extreme_candidate = n()) %>%
  mutate(.,
    extreme_candidate = case_when(
      extreme_candidate >= 1 ~ 1,
      TRUE ~ 0
    )
  ) %>%
  st_as_sf(coords = c("long", "lat"), crs = 4326)


covariates <- c(
  "population_thin",
  "population_intermediate",
  "population_density_2009",
  "area",
  "invalid_share_2009",
  "abstention_share_2009"
)


model_eq <- paste0(
  "rr_vote_share_2009 ~ extreme_candidate + ",
  paste(covariates, collapse = " + "),
  " + as.factor(county_id)"
)


## join to data with extreme-right success in 2005/2009
extreme_right_spatial_nest <- afd_spatial_nest %>%
  select(election_type, east, election_date, data_std) %>%
  # keep a single election as this refers only to 2009
  group_by(east, election_type) %>%
  slice(1) %>%
  mutate(
    election_date =
      case_when(
        election_type == "EP" ~ ymd("2009-06-07"),
        election_type == "Parliament" ~ ymd("2009-09-27")
      )
  ) %>%
  mutate(data_std = map(
    data_std,
    ~ select(
      ., rr_vote_share_2009,
      any_of(covariates),
      county_id,
      eligible_2009
    ) %>%
      ungroup() %>%
      # transform crs to match the google-api based coded data
      st_transform(., crs = 4326) %>%
      st_join(., extreme_right_residences) %>%
      mutate(.,
        extreme_candidate = case_when(
          extreme_candidate >= 1 ~ 1,
          TRUE ~ 0
        )
      )
  )) %>%
  mutate( # compute the neighbourhood matrix
    extreme_right_spatial.nb = map(
      data_std,
      # all contiguous neighbours (poly2nb) are considered neighbours
      ~ spdep::poly2nb(.,
        queen = T
      )
    ),
    # compute the weight matrix
    extreme_right_spatial.lw = map(
      extreme_right_spatial.nb,
      ~ spdep::nb2listw(.,
        style = "W",
        zero.policy = T
      )
    )
  )



```



```{r estimate-spatial-error-model-activists-success, eval = FALSE}

plan(multisession, workers = 18)

tic()
extreme_right_spatial_nest_sem <- extreme_right_spatial_nest %>%
  select(election_type, east, election_date, data_std, extreme_right_spatial.lw) %>%
  mutate(data_std = map(
    data_std,
    ~ ungroup(.) %>%
      as_tibble(.) %>%
      select(-geometry)
  )) %>%
  ungroup()


extreme_right_spatial_nest_sem <- extreme_right_spatial_nest_sem %>%
  # estimate the sem model
  mutate(
    sem_model =
      future_pmap(
        list(
          data_std,
          extreme_right_spatial.lw
        ),
        ~ spatialreg::errorsarlm(
          data = ..1,
          listw = ..2,
          model_eq,
          zero.policy = TRUE
        )
      )
  )
toc()


# save selected vars for smaller total dataset
extreme_right_spatial_nest_sem <- extreme_right_spatial_nest_sem %>%
  ungroup() %>%
  dplyr::select(election_date, east, sem_model)
save(extreme_right_spatial_nest_sem,
  file = "extreme_right_spatial_nest_sem.RData"
)
rm(extreme_right_spatial_nest_sem)
```


```{r load-spatial-error-model-extreme-right}

unzip(zipfile = "./data/extreme_right_spatial_sem_models.zip", 
      overwrite = T)


load("extreme_right_spatial_nest_sem.RData")

extreme_right_spatial_nest <- extreme_right_spatial_nest %>%
  left_join(.,
    extreme_right_spatial_nest_sem,
    by = c("election_date", "east")
  )

rm(extreme_right_spatial_nest_sem)
```


```{r regression-table-extreme-right}

# arrange the data
extreme_right_spatial_nest <- extreme_right_spatial_nest %>%
  arrange(desc(east), desc(election_type), election_date)

cm <- c(
  "extreme_candidate" = "Resident Extreme-Right Activist (2009)",
  "invalid_share_2009" = "Invalid Share (2009)",
  "abstention_share_2009" = "Abstention Rate (2009)",
  "population_thin" = "Rural area",
  "population_intermediate" = "Small urban area",
  "population_density_2009" = "Population density (1000/km$^2$)",
  "area" = "Area (km$^2$)",
  "(Intercept)" = "Intercept",
  "lambda" = "$\\lambda$"
)


# change the names of the sem model to the year of the election, i.e. the lowest dimension in the kableExtra regression table
names(extreme_right_spatial_nest$sem_model) <- lubridate::year(extreme_right_spatial_nest$election_date)


# add additional information for the regression table
model_id_chr <- c(paste0(
  year(extreme_right_spatial_nest$election_date),
  paste0(stringr::str_sub(extreme_right_spatial_nest$election_type, 1, 4)),
  paste0(extreme_right_spatial_nest$east)
))
countyFE_N <- c(
  "Number of Counties",
  map(
    extreme_right_spatial_nest$data_std,
    ~ length(unique(.$county_id)) %>%
      as.character()
  )
) %>%
  set_names(., c("term", model_id_chr))

rows <- tibble(
  model_id = model_id_chr,
  check_countyFE = "$\\checkmark$",
  term = "County-Fixed Effects"
) %>%
  pivot_wider(
    id_cols = term,
    values_from = c("check_countyFE"),
    names_from = "model_id"
  ) %>%
  bind_rows(
    .,
    countyFE_N
  )


attr(rows, "position") <- c(2 * length(cm) + 1, 2 * length(cm) + 2)
names(rows) <- c("term", names(extreme_right_spatial_nest$sem_model))


modelsummary(extreme_right_spatial_nest$sem_model,
  add_rows = rows,
  stars = TRUE,
  fmt = 2,
  title = "Support for the extreme right (2009) as a function of local prevalence of extreme-right networks",
  coef_map = cm,
  gof_map = gm,
  gof_omit = "DF|Deviance|BIC|Log.Lik.|AIC",
  escape = FALSE,
  output = "kableExtra"
) %>%
  # column labels second dimension: Parliament-EP Elections
  add_header_above(c(
    " " = 1,
    "National Election" = 2,
    "EP Election" = 2
  )) %>%
  # column labels upper dimension: West and East Germany
  add_header_above(c(
    " " = 1,
    "West Germany" = 2,
    "East Germany" = 2
  )) %>%
  # footnote
  add_footnote("Spatial simultaneous autoregressive error model by ML estimation.",
    notation = "none"
  )
```


```{r session-info}
print(sessionInfo(), local = FALSE)
```


::: {#refs}
:::
